/*
Copyright (c) 2009, Joseph J. Bergeron
All rights reserved.

Redistribution  and  use  in  source  and  binary  forms,  with  or  without  
modification,  are  permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation 
     and/or other materials provided with the distribution.
    * Neither the name of the creators nor the names of its contributors
      may be used to endorse or promote products derived from this software 
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package hatkins.data
{
	/**
	 * A node in an asset link
	 */
	public class AssetNode
	{
		private var _parent:AssetNode;
		private var _name:String;
		private var _content:Object;
		
		/**
		 * Create a asset node
		 */
		public function AssetNode(nodeName:String, nodeParent:AssetNode, nodeContent:Object) {
			_name = nodeName;
			_parent = nodeParent;
			_content = nodeContent;
		}
		
		/**
		 * Get the node content
		 */
		public function get content():Object {
			return _content;
		}
		
		/**
		 * Get the node name
		 */
		public function get name():String {
			return _name;
		}
		
		/**
		 * Get the parent of the node
		 */
		public function get parent():AssetNode {
			return _parent;
		}
		
		/**
		 * Get the path as an array of names
		 */
		public function getPathNameArray():Array {
			var pathNames:Array = [];
			var walk:AssetNode = _parent;
			pathNames.push(name);
			while (walk!=null) {
				pathNames.push(walk.name);
				walk = walk._parent;
			}
			return pathNames.reverse();
		}
		
		/**
		 * Get the node path
		 */
		public function getPathString():String {
			return getPathNameArray().join("/");
		}
		
		/**
		 * @copy
		 */
		public function toString():String {
			return _name;
		}
		
		/**
		 * Determine whether the node is a branch
		 */
		public function get isBranch():Boolean {
			return _content is AssetNodeList;
		}
		
		/**
		 * Determine whether the node is a branch and also has atleast 1 child
		 */
		public function get hasChildren():Boolean {
			return isBranch && AssetNodeList(_content).numNodes > 0;
		}
		
		/**
		 * Determine whether the node decends from another
		 */
		public function descendsFrom(node:AssetNode):Boolean {
			var walk:AssetNode = parent;
			while (walk!=null && node!=walk) {
				walk = walk.parent;
			}
			return walk!=null;
		}
		
		/**
		 * Get the leaf all reachable dependent leaf nodes
		 */
		public function collectLeaves():Array {
			var leaves:Array = [];
			_collectLeavesR(leaves, this);
			return leaves;
		}
		
		private function _collectLeavesR(leaves:Array, node:AssetNode):void {
			if (isBranch) {
				var list:AssetNodeList = AssetNodeList(node.content);
				for (var childIndex:int=0; childIndex<list.numNodes; ++childIndex) {
					_collectLeavesR(leaves, list.getNodeByIndex(childIndex));
				}
			}
			else {
				leaves.push(node);
			}
		}
		
		/**
		 * Get any child of the node by name
		 */
		public function getChildByName(childName:String):AssetNode {
			var list:AssetNodeList = content as AssetNodeList;
			return list != null ? list.getNodeByName(childName) : null;
		}
		
		/**
		 * Get any child of this node by index
		 */
		public function getChildByIndex(childIndex:int):AssetNode {
			var list:AssetNodeList = content as AssetNodeList;
			return list != null ? list.getNodeByIndex(childIndex) : null;
		}
	}
}